/*
 * Copyright 2020 Mike Penz
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.mikepenz.iconics;

import ohos.app.Context;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;

import com.mikepenz.iconics.animation.IconicsAnimationProcessor;
import com.mikepenz.iconics.typeface.ITypeface;
import com.mikepenz.iconics.typeface.IconicsHolder;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 字体库
 *
 * @since 2021-06-04
 */
public class Iconics {
    /**
     * Set if Iconics should respect the original bounds of the icon.
     * This applies to all Drawables (including views) as a default value.
     */
    private boolean respectFontBoundsDefault = false;
    private static final int DOMAIN = 110;
    private static final Iconics INSTANCE = new Iconics();
    private static final HashMap<String, Class<? extends IconicsAnimationProcessor>> PROCESSORS = new HashMap<>();
    private static final String TAG = Iconics.class.getSimpleName();
    private boolean isInitDone;
    private List<ITypeface> registeredFonts;
    private List<Class<? extends IconicsAnimationProcessor>> registeredProcessors;
    private Context applicationContext;

    private Iconics() {
    }

    public boolean isRespectFontBoundsDefault() {
        return respectFontBoundsDefault;
    }

    public void setRespectFontBoundsDefault(boolean respectFontBoundsDefault) {
        this.respectFontBoundsDefault = respectFontBoundsDefault;
    }

    /**
     * 获取实例
     *
     * @return Iconics实例
     */
    public static Iconics getInstance() {
        return INSTANCE;
    }

    /**
     * 获取上下文
     *
     * @return 上下文
     */
    public Context getApplicationContext() {
        return IconicsHolder.getInstance().getApplicationContext();
    }

    /**
     * Initializes the `Context` required for different operations inside Iconics.
     *
     * @param context 上下文
     */
    public void init(Context context) {
        IconicsHolder.getInstance().setContext(context);
    }

    /**
     * This makes sure the FONTS are initialized. If the given fonts Map is empty we set the
     * initialized FONTS on it
     *
     * @param fonts
     * @return 字体键值对
     */
    private Map<String, ITypeface> initRequiredFonts(Map<String, ITypeface> fonts) {
        if (fonts == null || fonts.isEmpty()) {
            return IconicsHolder.getFonts();
        } else {
            return fonts;
        }
    }

    /**
     * Returns if the `Iconics` instance was initialized.
     *
     * @return 是否初始化
     */
    public boolean isInitDone() {
        try {
            IconicsHolder.getInstance().getApplicationContext();
            isInitDone = true;
        } catch (Exception e) {
            isInitDone = false;
        }
        return isInitDone;
    }

    private void markInitDone() {
        if (IconicsHolder.getFonts().isEmpty()) {
            throw new IllegalArgumentException(
                "At least one font needs to be registered first" + System.lineSeparator()
                    + "    via ${javaClass.canonicalName}.registerFont(Iconics.kt:117)"
            );
        }
    }

    /**
     * Test if the icon exists in the currently loaded fonts
     *
     * @param icon The icon to verify
     * @return true if the icon is available
     */
    public boolean isIconExists(String icon) {
        return findFont(iconPrefix(icon)).getIcon(clearedIconName(icon)) != null;
    }

    /**
     * Registers a fonts into the FONTS array for performance
     *
     * @param font 字体
     * @return 是否注册成功
     */
    public boolean registerFont(ITypeface font) {
        IconicsHolder.registerFont(font);
        return true;
    }

    /**
     * Registers a processor into the PROCESSORS array for performance
     *
     * @param processor 动画
     */
    public void registerProcessor(IconicsAnimationProcessor processor) {
        PROCESSORS.put(processor.getAnimationTag(), processor.getClass());
    }

    /**
     * 查找动画
     *
     * @param animationTag 动画标签
     * @return 查找结果
     */
    public IconicsAnimationProcessor findProcessor(String animationTag) {
        Class<? extends IconicsAnimationProcessor> clazz = PROCESSORS.get(animationTag);
        try {
            return clazz.newInstance();
        } catch (IllegalAccessException | InstantiationException e) {
            HiLog.error(new HiLogLabel(HiLog.LOG_APP, DOMAIN, TAG),
                "Can't create processor for animation tag $animationTag", e);
            return null;
        }
    }

    /**
     * Return all registered FONTS
     *
     * @return 字体集合
     */
    public List<ITypeface> getRegisteredFonts() {
        return new ArrayList<>(IconicsHolder.getFonts().values());
    }

    /**
     * Return all registered FONTS
     *
     * @param context 上下文
     * @return 字体集合
     */
    public List<ITypeface> getRegisteredFonts(Context context) {
        init(context);
        return new ArrayList<>(IconicsHolder.getFonts().values());
    }

    /**
     * Return all registered PROCESSORS
     *
     * @return 动画集合
     */
    public List<Class<? extends IconicsAnimationProcessor>> getRegisteredProcessors() {
        return new ArrayList<>(PROCESSORS.values());
    }

    /**
     * Return all registered PROCESSORS
     *
     * @param context 上下文
     * @return 动画集合
     */
    public List<Class<? extends IconicsAnimationProcessor>> getRegisteredProcessors(Context context) {
        init(context);
        return new ArrayList<>(PROCESSORS.values());
    }

    /**
     * Tries to find a font by its key in all registered FONTS
     *
     * @param key 关键字
     * @param context 上下文
     * @return 字体
     */
    public ITypeface findFont(String key, Context context) {
        init(context);
        return IconicsHolder.getFonts().get(key);
    }

    /**
     * Fetches the font from the Typeface of an IIcon
     *
     * @param key 关键字
     * @return 字体
     */
    public ITypeface findFont(String key) {
        return IconicsHolder.getFonts().get(key);
    }

    /**
     * 截取前缀
     *
     * @param icon 字体名
     * @return 截取后的字符串
     */
    public static String iconPrefix(String icon) {
        final int max = 3;
        return icon.substring(0, max);
    }

    /**
     * 替换字符
     *
     * @param icon 字体名
     * @return 替换后的字符串
     */
    public static String clearedIconName(String icon) {
        return icon.replaceAll("-", "_");
    }
}
